<?php

namespace app\usedb\model;

// 所有自定义的模型类 一定要继承基础模型类 think\Model
// 基础模型类中有数据库的全部方法
use app\validate\Student;
use think\exception\ValidateException;
use think\facade\Filesystem;
use think\Model;
use think\model\concern\SoftDelete;

// 一般情况下，模型类名和表名（去前缀）是一致的
class Xsb extends Model
{
    // 引入SoftDelete 这个特质(trait)可以实现软删除
    use SoftDelete;

    //设置软删除字段
    protected $deleteTime = 'del';  // 软删除相当于update 一个叫del的字段加入时间戳，存在时间戳则无法查询到

    // $table 属性：配置表名
    // 如果类名和表名一致，则可以省略表名
    protected $table = 'zx_xsb';
    // $pk 属性：配置主键（primary key）
    // 主键名为id时可以省略
    protected $pk = 'xh';

    // 开启自动时间戳 并且 直接规定数据库中使用时间戳字段为 int类型
    protected $autoWriteTimestamp = 'int';
    // 定义时间戳字段名
    protected $createTime = 'addtime';
    protected $updateTime = 'edittime';

    // 自定义查询方法(传入$get 返回$list)
    // 一般情况下，自定义的模型方法均为静态的，目的是不用new，提升开发效率和优化系统执行效率
    public static function m_select($get)
    {

        // 拆开的链式操作（可以插入if语句）
//        $obj = Db::name('xsb')
        $list = self::alias('x')    // 把Db::name()改成self,指使用该方法的数据表本身
        ->field('x.*,s.szx as sname')
            ->leftjoin('zx_szx s', 'x.szx=s.id')
            // withSearch(['搜索器名字1','搜索器名字2'],'条件数组')
            ->withSearch(['xm', 'sex', 'age', 'szx'], $get)   // 将if语句去除改成withSearch()方法复用
//            ->select();
            // 分页查询
//            ->paginate(10); // 替换select，依据参数每页获取指定条记录
            ->paginate([
                'list_rows' => 10,    // 每页数量
                'var_page' => 'p',    // 分页变量（分页参数命名）
                'query' => $get       // url额外参数（get参数切换分页时显示在浏览器上）
            ]); // 替换select，依据参数每页获取指定条记录

//        // 姓名搜索条件
//        if (isset($get['xm']) and $get['xm'] !== '') {
//            $obj->where('xm', 'like', "%{$get['xm']}%");  // 在链式操作中插入where语句
//        }
//        // 性别搜索条件
//        if (isset($get['sex']) and $get['sex'] !== '') {
//            $obj->where('sex', '=', $get['sex']);
//        }
//        // 年龄搜索条件1
//        if (isset($get['age1']) and $get['age1'] !== '') {
//            $obj->where('age', '>=', $get['age1']);
//        }
//        // 年龄搜索条件2
//        if (isset($get['age2']) and $get['age2'] !== '') {
//            $obj->where('age', '<=', $get['age2']);
//        }
//        // 所在系搜索条件
//        if (isset($get['szx']) and $get['szx'] !== '') {
//            $obj->whereIn('x.szx', $get['szx']);
//        }
//        dump($obj);     // obj是一个 think\db\Query 查询语句对象
//        $list = $obj->select();
//        dump($list);    // 用list接收，执行查询返回到一个think\Collection 查询结果对象

        // 将得到的结果集return返回给调用者
        return $list;
    }

    // 搜索器
    // 动态方法 不需要手动调用
    // 使用withSearch()连贯操作时自动调用
    // 定义 searchNameAttr 搜索起名尽量和搜索条件数组的字段名一致  search和Attr是固定的，中间可以改
    // searchNameAttr($模型对象, $搜索数组中该字段对应的值, $搜索数组)
    public function searchXmAttr($query, $value, $data)
    {
        // 测试是否已经被动触发该方法
//        dump($query);
//        dump($value);
//        dump($data);
        if ($value) {   // 设置$value有值才执行搜索
            $query->where('xm', 'like', "%{$value}%");
        }
    }

    public function searchSexAttr($query, $value, $data)
    {
        if ($value) {
            $query->where('sex', '=', $value);
        }
    }

    public function searchAgeAttr($query, $value, $data)
    {
        if (isset($data['age1']) and $data['age1'] != '') {
            $query->where('age', '>=', $data['age1']);
        }
        if (isset($data['age2']) and $data['age2'] != '') {
            $query->where('age', '<=', $data['age2']);
        }
    }

    public function searchSzxAttr($query, $value, $data)
    {
        if (isset($data['szx']) and $data['szx'] != '') {
            $query->whereIn('x.szx', $data['szx']);
        }
    }

    // 所在系获取器：如果所在系为空 则显示“暂无系别”  获取到sname值就自动触发
    public function getSnameAttr($value)
    {
        return $value ?: '暂无系别';
    }

    // 模型类里自定义按学号软删除功能
    public static function del($xh)
    {
        try {
            // 将可能发生错误的语句放入try中
            Xsb::destroy($xh);
//            dump('删除成功');
            $arr = ['error' => 0, 'msg' => '删除成功'];
        } catch (\Exception $e) { // 捕获异常 (Exception异常类 绑定给e对象)
            // 使用异常对象的getMessage方法得到错误信息
//            dump($e->getMessage());
            // 若不需要给用户观测到错误信息，直接自定义一个报错信息提示
            $arr = ['error' => 1, 'msg' => '系统波动，请稍后再试'];
        }
        return $arr;
    }

    public static function add($param): array
    {
        // 先验证数据输入合法性 再 处理写入数据库保存数据
        try {
            // 验证数据输入合法性
            validate(Student::class)
                ->batch(true)
                ->scene('非图片')
                ->check($param);
            // 验证图片的合法性
//            if(!empty($file)) {
//                validate(Student::class)
//                    ->batch(true)
//                    ->scene('图片')
//                    ->check($file);
//                // 储存图片，返回一个存储路径
//                $save_url = Filesystem::disk('storage_test')->putFile('photo2', $file['img']);
//                // 将路径加入参数数组内
//                $param['headimg'] = $save_url;
////                halt($param);
//            } else {
//                return $arr = ['error'=>1, 'msg'=>'请上传图片再尝试'];
//            }
//            halt($param);

            // 使用封装的 移动缓存文件至正式文件夹 静态方法
            self::copy($param);

            // 移动文件完成，向数据库写入数据
            self::create($param);
            // 写入成功，提示信息
            $arr = ['error' => 0, 'msg' => '添加成功'];
        } catch (ValidateException $e) {
            // 输入验证失败，提示用户错误信息（implode把数组转换成字符串）
            $arr = ['error' => 1, 'msg' => implode('，', $e->getError())];
        } catch (\Exception $e) {
            // 其他问题提示用户系统错误
            $arr = ['error' => 2, 'msg' => '系统错误'];
        }
        // 返回数组给控制器提示信息和跳转页面
        return $arr;
    }

    // 图片获取器 将路径中的\变为/
    public function getHeadimgAttr($value)
    {
        return str_replace("\\", "/", $value);
    }
    // 图片修改器 将保存路径中的\变为/
    // 添加 或者 修改 数据时，会对数据进行预处理
    public function setHeadimgAttr($value)
    {
        return str_replace("\\", "/", $value);
    }

    // 修改器
    // 添加 或者 修改 数据时，会对数据进行预处理
//    public function setXmAttr($value)
//    {
//        return "修改器-{$value}";
//    }

// 修改器的名字与调用处字段名有关，与数据库字段名没有直接关系
    public function setLzcAttr($value)
    {
        $this->set('heading', $value);  // 执行存储时可以隐藏数据库的真实字段
    }

    public static function edit($post, $key)
    {
        // 接收3组参数  需要修改的数据 + 主键 + 文件
        // 先验证数据输入合法性 再 处理写入数据库保存数据
        try {
            // 验证数据输入合法性
            validate(Student::class)
                ->batch(true)
                ->scene('非图片')
                ->check($post);
            // 验证图片的合法性
//            if(!empty($file)) {
//                validate(Student::class)
//                    ->batch(true)
//                    ->scene('图片')
//                    ->check($file);
//                // 储存图片，返回一个存储路径
//                $save_url = Filesystem::disk('storage_test')->putFile('photo2', $file['img']);
//                // 将路径加入参数数组内
//                $post['headimg'] = $save_url;
////                halt($param);
//            }

            // 使用封装的 移动缓存文件至正式文件夹 静态方法
            self::copy($post);

            // 移动文件完成，更新数据库数据
            self::update($post, ['xh' => $key]);
            // 更新成功，提示信息
            $arr = ['error' => 0, 'msg' => '更新成功'];
        } catch (ValidateException $e) {
            // 输入验证失败，提示用户错误信息（implode把数组转换成字符串）
            $arr = ['error' => 1, 'msg' => implode('，', $e->getError())];
        } catch (\Exception $e) {
            // 其他问题提示用户系统错误
            $arr = ['error' => 2, 'msg' => '系统错误'];
        }
        // 返回数组给控制器提示信息和跳转页面
        return $arr;
    }

    // 存储缓存文件至正式文件夹 的 静态方法
    public static function copy($file)
    {
        $temp_path = app()->getRootPath() . 'public/temp/';
        $formal_path = app()->getRootPath() . 'public/static/';
        if (!is_dir("{$formal_path}photo/" . date('Ymd'))) {
            mkdir("{$formal_path}photo/" . date('Ymd'), 777, true);
        }
        if (file_exists($temp_path . $file['headimg'])) {
            rename($temp_path . $file['headimg'], $formal_path . $file['headimg']);
        }
    }
}